home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_09_12 / 9n12064a < prev    next >
Text File  |  1991-07-25  |  19KB  |  615 lines

  1. /*** LISTING 1 ** UARTAPI.C **************************
  2.    Application Programming Interface for
  3.    UART Asynch Driver.
  4. *****************************************************/
  5.  
  6. #include <conio.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stddef.h>
  10. #include <dos.h>
  11.  
  12. #include "uart.h"
  13. #include "uartmacs.c"
  14.  
  15. /* unused interrupt vector to redirect Ctrl-Break to */
  16. #define UNUSEDVECT   0x48    
  17.  
  18. /* Ctrl-Break vector */
  19. #define CTRL_BRKVECT 0x23    
  20.  
  21. /* Table for converting baud rate to divisor 
  22.    settings */
  23. static struct 
  24. {
  25.    unsigned long baud_rate;
  26.    unsigned char divisor_high_byte;
  27.    unsigned char divisor_low_byte;
  28. } gas_baud_to_divisor[] = 
  29.    {
  30.        {   50L,        0x09,   0x00 },
  31.        {   75L,        0x06,   0x00 },
  32.        {   110L,       0x04,   0x17 },
  33.        {   134L,       0x03,   0x59 },
  34.        {   150L,       0x03,   0x00 },
  35.        {   300L,       0x01,   0x80 },
  36.        {   600L,       0x00,   0xC0 },
  37.        {   1200L,      0x00,   0x60 },
  38.        {   1800L,      0x00,   0x40 },
  39.        {   2000L,      0x00,   0x3A },
  40.        {   2400L,      0x00,   0x30 },
  41.        {   3600L,      0x00,   0x20 },
  42.        {   4800L,      0x00,   0x18 },
  43.        {   7200L,      0x00,   0x10 },
  44.        {   9600L,      0x00,   0x0C },
  45.        {   19200L,     0x00,   0x06 },
  46.        {   38400L,     0x00,   0x03 },
  47.        {   57600L,     0x00,   0x02 },
  48.        {   115200L,    0x00,   0x01 },
  49.        {   0L,         0x00,   0x00 },
  50.    } ;
  51.  
  52. /* Space to save original asynch interrupt vector */
  53. static void (interrupt far * gp_orig_asynch_vector)();       
  54.  
  55. /* to save original Ctrl-Break vector */
  56. static void (interrupt far *gp_ctrlbrk_vector)();    
  57.  
  58. /*****************************************************
  59. rc = Init_UART()
  60. rc = 1 : UART(s) intialized OK
  61. rc = -1: Failure in initialization.
  62.  
  63. Before calling this function, you must allocate and
  64. initialize the gp_port_info array to describe
  65. the UART(s) you want to drive, and you must set
  66. g_uart_irq to the IRQ level used (all ports must
  67. use the same IRQ level).
  68.  
  69. This function latches the UART's interrupt driver
  70. into the system interrupt table and initializes the
  71. UART(s).   If successful, it registers the
  72. Exit_UART function to be called during system
  73. shutdown.
  74. *****************************************************/
  75. int Init_UART(void)
  76. {
  77.    static char a_funcname[] = "Init_UART:";
  78.    register int value_from_port;   
  79.    unsigned int i;         
  80.    int retcode;
  81.    unsigned char cur_port; 
  82.    struct t_port_info *p_cur_port_info; 
  83.    void (interrupt far * p_unusedvect)();       
  84.  
  85.    /* Verify that calling program has initialized
  86.       info structures and variables */
  87.    if (g_num_ports < 1)
  88.    {
  89.        fprintf(stderr,"%s g_num_ports (%u) < 1\n",
  90.                a_funcname,g_num_ports);
  91.        return(-1);
  92.    }
  93.    if (gp_port_info == NULL)
  94.    {
  95.        fprintf(stderr,"%s gp_port_info is NULL\n",
  96.                a_funcname);
  97.        return(-1);
  98.    }
  99.    if ( (g_uart_irq < 3) || (g_uart_irq > 7) )
  100.    {
  101.        fprintf(stderr,"%s g_uart_irq (%u) not 3-7\n",
  102.                a_funcname,g_uart_irq);
  103.        return(-1);
  104.    }
  105.  
  106.  
  107.    /* Point at entry for first port */
  108.    p_cur_port_info = gp_port_info;  
  109.  
  110.  
  111.    /* Loop through array of port info entries and
  112.       initialize each port */
  113.    for (cur_port=1;cur_port<=g_num_ports;cur_port++)
  114.    {
  115.        /* Initialize internal variables in port
  116.           info entry */
  117.        p_cur_port_info->tx_head = 0;
  118.        p_cur_port_info->tx_tail = 0;
  119.        p_cur_port_info->rx_head = 0;
  120.        p_cur_port_info->rx_tail = 0;
  121.        p_cur_port_info->non_int_chars = 0;
  122.  
  123.        /* Check for valid port on this IRQ and at 
  124.           this base address */
  125.        retcode = Test_for_asynch_port(
  126.            p_cur_port_info->base_address,g_uart_irq);
  127.        if (retcode == -1)
  128.        {
  129.            fprintf(stderr,
  130.              "%s port %u-no UART at %.4Xh on IRQ %u\n",
  131.              a_funcname,cur_port,
  132.              p_cur_port_info->base_address,
  133.              g_uart_irq);
  134.            return(-1);
  135.        }
  136.  
  137.        /* Validate modem parameters */
  138.        if ( (p_cur_port_info->stop_bits < 1) ||
  139.             (p_cur_port_info->stop_bits > 2) )
  140.        {
  141.            fprintf(stderr,
  142.               "%s port %u-stop bits (%u) not 1 or 2\n",
  143.               a_funcname,cur_port,
  144.               p_cur_port_info->stop_bits);
  145.               return(-1);
  146.        }
  147.  
  148.        switch (p_cur_port_info->parity)
  149.            {
  150.                case 0 :
  151.                case 1 :
  152.                case 3 :
  153.                    break;
  154.  
  155.                default :
  156.                    fprintf(stderr,
  157.               "%s port %u-parity (%u) not 0,1,or 3\n",
  158.                        a_funcname,cur_port,
  159.                        p_cur_port_info->parity);
  160.                    return(-1);
  161.            }
  162.  
  163.        if ( (p_cur_port_info->data_bits < 5) || 
  164.             (p_cur_port_info->data_bits > 8) )
  165.        {
  166.            fprintf(stderr,
  167.                "%s port %u-data bits (%u) not 5-8\n",
  168.                a_funcname,cur_port,
  169.                p_cur_port_info->data_bits);
  170.            return(-1);
  171.        }
  172.  
  173.        /* Translate specified baud rate into 
  174.           divisor settings */
  175.        for (i=0;
  176.             gas_baud_to_divisor[i].baud_rate != 0L;
  177.             i++)
  178.        {
  179.            if (p_cur_port_info->baud_rate == 
  180.                gas_baud_to_divisor[i].baud_rate)
  181.                break;
  182.        }
  183.        if (gas_baud_to_divisor[i].baud_rate == 0L)
  184.        {
  185.            fprintf(stderr,
  186.                "%s port %u-invalid baud rate %lu\n",
  187.                a_funcname,cur_port,
  188.                p_cur_port_info->baud_rate);
  189.            return(-1);
  190.        }
  191.  
  192.        /* Make sure interrupt generation is disabled */
  193.        outp(p_cur_port_info->base_address+
  194.             INTERRUPT_ENABLE_REGISTER,0x00);
  195.  
  196.        /* Delay for port to catch up */
  197.        IO_DELAY(3);        
  198.  
  199.        /* Enable writing to divisor latch */
  200.        outp(p_cur_port_info->base_address+
  201.             LINE_CONTROL_REGISTER,0x80);    
  202.  
  203.        /* Delay for port to catch up */        
  204.        IO_DELAY(3);         
  205.  
  206.        /* Set the low byte of the divisor latch */
  207.        outp(p_cur_port_info->base_address+
  208.             DIV_LATCH_LOW_BYTE,
  209.             gas_baud_to_divisor[i].divisor_low_byte);
  210.  
  211.        /* Delay for port to catch up */        
  212.        IO_DELAY(3);         
  213.  
  214.        /* Set the low byte of the divisor latch */
  215.        outp(p_cur_port_info->base_address+
  216.             DIV_LATCH_HIGH_BYTE,
  217.             gas_baud_to_divisor[i].divisor_high_byte);
  218.  
  219.        /* Delay for port to catch up */        
  220.        IO_DELAY(3);         
  221.  
  222.        /* Set parity, data bits, stop bits, and 
  223.           disable writing to divisor latch */
  224.        value_from_port = (int) 
  225.           ( ((p_cur_port_info->stop_bits - 1) << 2 ) |
  226.             ( p_cur_port_info->parity << 3 ) |
  227.             ( p_cur_port_info->data_bits - 5 ) ) ;
  228.        outp(p_cur_port_info->base_address + 
  229.            LINE_CONTROL_REGISTER, value_from_port);
  230.  
  231.        /* Delay for port to catch up */        
  232.        IO_DELAY(3);         
  233.  
  234.        /* Initialize Modem Control Register - raise the
  235.           OUT2 signal */
  236.        outp(p_cur_port_info->base_address +
  237.             MODEM_CONTROL_REGISTER,0x08);
  238.  
  239.        /* Delay for port to catch up */        
  240.        IO_DELAY(3);         
  241.  
  242.        /* Enable the FIFO and set it to generate rcv
  243.           interrupts only when fifo has more than 8 
  244.           characters (if UART doesn't have a fifo - 
  245.           it is an older UART - this instruction will 
  246.           do nothing). */
  247.        outp(p_cur_port_info->base_address +
  248.             FIFO_CONTROL_REGISTER,FIFO_ENABLE);
  249.  
  250.        /* Delay for port to catch up */        
  251.        IO_DELAY(3);         
  252.  
  253.        /* Read the interrupt identification register 
  254.           to determine if the FIFO is enabled.  If the 
  255.           fifo is enabled, use it to transmit multiple 
  256.           characters. */
  257.        value_from_port = 
  258.            inp(p_cur_port_info->base_address + 
  259.                INTER